#ifndef MP_H_
#define MP_H_

#include <types.h>

#define MP_SIGNATURE "_MP_"
#define MP_FP_START 0x000F0000
#define MP_FP_END 0x000FFFFF

#define MP_TYPE_CPU 0
#define MP_TYPE_BUS 1
#define MP_TYPE_IOAPIC 2
#define MP_TYPE_IOINT 3
#define MP_TYPE_LINT 4

#define MP_FEAT2_IMCRP (1 << 7)

#define MP_BUS_CBUS		"CBUS  "
#define MP_BUS_CBUS2	"CBUSII"
#define MP_BUS_EISA		"EISA  "
#define MP_BUS_FUTURE 	"FUTURE"
#define MP_BUS_INTERNAL	"INTERN"
#define MP_BUS_ISA 		"ISA   "
#define MP_BUS_MULTIBUS	"MBI   "
#define MP_BUS_MULTIBUS2 "MBII  "
#define MP_BUS_MICRO 	"MCA   "
#define MP_BUS_MPI		"MPI   "
#define MP_BUS_MPSA		"MPSA  "
#define MP_BUS_PCI		"PCI   "
#define MP_BUS_PCMCIA	"PCMCIA"
#define MP_BUS_EXPRESS	"XPRESS"
#define MP_BUS_VESA		"VL    "

#define MP_CPUFLAGS_ENABLE (1 << 0)
#define MP_CPUFLAGS_BOOT (1 << 1)
#define MP_CPUSIG_STEPPING (0xF << 0)
#define MP_CPUSIG_MODEL (0xF << 4)
#define MP_CPUSIG_FAMILY (0xF << 8)

#define MP_IOAPICFLAGS_ENABLE (1 << 0)

#define MP_INT_TYPE_INT 0
#define MP_INT_TYPE_NMI 1
#define MP_INT_TYPE_SMI 2
#define MP_INT_TYPE_EXTINT 3

#define MP_INTFLAGS_POLARITY (0x3 << 0)
#define MP_INTFLAGS_TRIGGER (0x3 << 2)

#define MP_INTMODE_PIC 1
#define MP_INTMODE_APIC 2

#define MP_ERR_FP_NOTFOUND 1
#define MP_ERR_INVALID_ADDR 2
#define MP_ERR_INVALID_CHECKSUM 3

/**
 * MP Floating Pointer structure
 */
typedef struct mp_fp
{
	byte signature[4];
	dword addr;
	byte length;
	byte revision;
	byte checksum;
	byte features[5];
} __attribute__((packed)) mp_fp_t;

/**
 * MP Configuration Entry for CPU types
 */
typedef struct mp_config_entry_cpu
{
	byte type;
	byte lapic_id;
	byte lapic_version;
	byte flags;
	dword signature;
	dword feature_flags;
	dword reserved[2];
} __attribute__((packed)) mp_config_entry_cpu_t;

/**
 * MP Configuration Entry for Bus types
 */
typedef struct mp_config_entry_bus
{
	byte type;
	byte id;
	byte type_string[6];
} __attribute__((packed)) mp_config_entry_bus_t;

/**
 * MP Configuration Entry for I/O-APIC types
 */
typedef struct mp_config_entry_ioapic
{
	byte type;
	byte id;
	byte version;
	byte flags;
	dword addr;
} __attribute__((packed)) mp_config_entry_ioapic_t;

/**
 * MP Configuration Entry for I/O-APIC Interrupt Assignment types
 */
typedef struct mp_config_entry_ioint
{
	byte type;
	byte int_type;
	word flags;
	byte src_bus_id;
	byte src_bus_irq;
	byte dest_ioapic_id;
	byte dest_ioapic_int;
} __attribute__((packed)) mp_config_entry_ioint_t;

/**
 * MP Configuration Entry for Local-APIC Interrupt Assignment types
 */
typedef struct mp_config_entry_lint
{
	byte type;
	byte int_type;
	word flags;
	byte src_bus_id;
	byte src_bus_irq;
	byte dest_lapic_id;
	byte dest_lapic_int;
} __attribute__((packed)) mp_config_entry_lint_t;

/**
 * MP Configuration Table structure
 */
typedef struct mp_config_table
{
	byte signature[4];
	word length;
	byte revision;
	byte checksum;
	byte oem_id[8];
	byte prod_id[12];
	dword oem_ptr;
	word oem_table_size;
	word entry_count;
	dword lapic_addr;
	word ext_length;
	byte ext_checksum;
	byte reserved;
} __attribute__((packed)) mp_config_table_t;

mp_fp_t * find_mp_fp(void *start, void *end);
int init_mptables(void);
byte mp_get_intmode(void);

#endif /*MP_H_*/
